package com.runner.screen;

import java.util.ArrayList;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.NinePatch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Label.LabelStyle;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.runner.RedRunner;
import com.runner.observer.Event;
import com.runner.observer.Observer;
import com.runner.observer.Subject;
import com.runner.unlocks.AprilUnlock;
import com.runner.unlocks.GeoUnlock;
import com.runner.unlocks.MagnetUnlock;
import com.runner.unlocks.MultUnlock;
import com.runner.unlocks.RingerUnlock;
import com.runner.unlocks.ShieldUnlock;
import com.runner.unlocks.Track1Unlock;
import com.runner.unlocks.Track2Unlock;
import com.runner.utility.Constants;
import com.runner.utility.Locator;

public class ParameterScreen implements Constants, Observer {

	private BitmapFont smallFont;
	private NinePatch bgPatch;
	private Stage stage;
	private Stage stageUnlock;
	private TextButton buttonBack, buttonStart, buttonConfirm, buttonCancel;
	private Label runner, boosts, tracks, coins, confirm, loadout;
	private Image coinImage;
	private LabelStyle labelStyle, textFieldConfirmStyle, textSmallFieldStyle, bigStyle;
	private Skin skin;
	private TextureAtlas atlas;
	private TextButtonStyle textButtonStyle, playStyle, exitStyle, confirmStyle;
	private final ArrayList<TransitionEffect> effects;
	private final Subject subject;
	private MenuScreen menu;
	private RedRunner game;
	private PLAYER_TYPE pType, pUnlockType;
	private ArrayList<BOOST_TYPE> bType;
	private TRACKTYPE tType;
	private ShapeRenderer selected;
	private Track1Unlock track1;
	private Track2Unlock track2;
	private AprilUnlock aprilUnlock;
	private GeoUnlock geoUnlock;
	private MagnetUnlock magnetUnlock;
	private ShieldUnlock shieldUnlock;
	private MultUnlock multUnlock;
	private NinePatch patch;
	private SpriteBatch sb;
	private Texture background;
	private boolean magnet = false;
	private boolean mult = false;
	private boolean shield = false;
	private boolean confirmUnlock;
	private boolean track2Selected = false;
	private boolean unlocked = false;

	public ParameterScreen(RedRunner game, MenuScreen menu, BitmapFont font, BitmapFont medFont, BitmapFont bigFont, BitmapFont confirmFont,
			Subject subject) {
		this.subject = subject;
		smallFont = font;
		this.menu = menu;
		this.game = game;
		bgPatch = new NinePatch(Locator.getAssets().get(PANEL_PATH, Texture.class));
		sb = new SpriteBatch();
		confirmUnlock = false;
		patch = new NinePatch(Locator.getAssets().get(PANEL_PATH, Texture.class));
		subject.addObserver(this);
		selected = new ShapeRenderer();
		pType = PLAYER_TYPE.RINGER;
		pUnlockType = PLAYER_TYPE.APRIL;
		tType = TRACKTYPE.TRACK1;
		bType = new ArrayList<BOOST_TYPE>();

		background = Locator.getAssets().get(BACKGROUNDMAIN_RINGER, Texture.class);

		stage = new Stage(Locator.getViewport());
		stageUnlock = new Stage(Locator.getViewport());

		atlas = new TextureAtlas(Gdx.files.internal("data/button.pack"));
		skin = new Skin(atlas);

		textButtonStyle = new TextButtonStyle();
		textButtonStyle.up = skin.getDrawable("button.up");
		textButtonStyle.down = skin.getDrawable("button.down");
		textButtonStyle.pressedOffsetX = 1;
		textButtonStyle.pressedOffsetY = -1;
		textButtonStyle.font = smallFont;
		playStyle = new TextButtonStyle(textButtonStyle);
		playStyle.fontColor = Color.DARK_GRAY;
		playStyle.font = smallFont;
		exitStyle = new TextButtonStyle(textButtonStyle);
		exitStyle.fontColor = Color.DARK_GRAY;
		exitStyle.font = bigFont;

		labelStyle = new LabelStyle();
		labelStyle.font = medFont;
		labelStyle.fontColor = Color.DARK_GRAY;

		textSmallFieldStyle = new LabelStyle();
		textSmallFieldStyle.font = font;
		textSmallFieldStyle.fontColor = Color.DARK_GRAY;

		bigStyle = new LabelStyle();
		bigStyle.font = bigFont;
		bigStyle.fontColor = Color.DARK_GRAY;

		textFieldConfirmStyle = new LabelStyle();
		textFieldConfirmStyle.font = confirmFont;
		textFieldConfirmStyle.fontColor = Color.DARK_GRAY;

		confirmStyle = new TextButtonStyle(textButtonStyle);
		confirmStyle.fontColor = Color.DARK_GRAY;
		confirmStyle.font = confirmFont;

		// create a transition screen
		effects = new ArrayList<TransitionEffect>();
		effects.add(new FadeOutTransitionEffect(0.5f));
		effects.add(new FadeInTransitionEffect(0.5f));

		new RingerUnlock(stage, textSmallFieldStyle, subject);
		aprilUnlock = new AprilUnlock(stage, textSmallFieldStyle, subject);
		geoUnlock = new GeoUnlock(stage, textSmallFieldStyle, subject);
		track1 = new Track1Unlock(stage, textSmallFieldStyle, subject);
		track2 = new Track2Unlock(this, stage, textSmallFieldStyle, subject);
		magnetUnlock = new MagnetUnlock(stage, textSmallFieldStyle, subject);
		shieldUnlock = new ShieldUnlock(stage, textSmallFieldStyle, subject);
		multUnlock = new MultUnlock(stage, textSmallFieldStyle, subject);

		createButtons();
		// create title
		runner = new Label("Runners", labelStyle);
		runner.setPosition(ACTUAL_VIRTUAL_WIDTH * RUNNER_X, ACTUAL_VIRTUAL_HEIGHT * (RUNNER_Y - 0.02f));
		tracks = new Label("Tracks", labelStyle);
		tracks.setPosition(ACTUAL_VIRTUAL_WIDTH * RUNNER_X, ACTUAL_VIRTUAL_HEIGHT * (RUNNER_Y - SEPARATION_Y - 0.07F));
		boosts = new Label("Boosts", labelStyle);
		boosts.setPosition(ACTUAL_VIRTUAL_WIDTH * RUNNER_X, ACTUAL_VIRTUAL_HEIGHT * (RUNNER_Y - SEPARATION_Y * 2 - 0.12F));

		buttonBack.setPosition(ACTUAL_VIRTUAL_WIDTH * (0.3F), ACTUAL_VIRTUAL_HEIGHT * 0.015f);
		buttonStart.setPosition(ACTUAL_VIRTUAL_WIDTH * (0.63F), ACTUAL_VIRTUAL_HEIGHT * 0.015f);

		coinImage = new Image(Locator.getAssets().get(SINGLE_COIN_PATH, Texture.class));
		coinImage.setPosition(ACTUAL_VIRTUAL_WIDTH * 0.89f, ACTUAL_VIRTUAL_HEIGHT * 0.93f);
		coinImage.setScale((1 ) * 0.94F);
		coins = new Label("" + Locator.getCoins(), labelStyle);
		coins.setPosition(ACTUAL_VIRTUAL_WIDTH * 0.93f, ACTUAL_VIRTUAL_HEIGHT * 0.93f);
		coins.setScale((1 ) * 1.2F);

		buttonConfirm.setPosition(ACTUAL_VIRTUAL_WIDTH * 0.53f, ACTUAL_VIRTUAL_HEIGHT * 0.25f);
		buttonCancel.setPosition(ACTUAL_VIRTUAL_WIDTH * 0.27f, ACTUAL_VIRTUAL_HEIGHT * 0.25f);
		confirm = new Label("Unlock April for 50 coins?", textFieldConfirmStyle);
		confirm.setWidth(ACTUAL_VIRTUAL_WIDTH * 0.8f);
		confirm.setPosition(ACTUAL_VIRTUAL_WIDTH * 0.27f, ACTUAL_VIRTUAL_HEIGHT * 0.49f);
		confirm.setWrap(true);

		loadout = new Label("Loadout", bigStyle);
		loadout.setPosition(ACTUAL_VIRTUAL_WIDTH * 0.445f, ACTUAL_VIRTUAL_HEIGHT * 0.91f);

		hideUnlock();

		stageUnlock.addActor(confirm);
		stageUnlock.addActor(buttonConfirm);
		stageUnlock.addActor(buttonCancel);

		stage.addActor(loadout);
		stage.addActor(coinImage);
		stage.addActor(coins);

		stage.addActor(buttonStart);
		stage.addActor(buttonBack);

		stage.addActor(runner);
		stage.addActor(tracks);
		stage.addActor(boosts);
		
		sb.setTransformMatrix(stage.getCamera().view);
		sb.setProjectionMatrix(stage.getCamera().projection);
		selected.setTransformMatrix(stage.getCamera().view);
		selected.setProjectionMatrix(stage.getCamera().projection);

	}

	private void createButtons() {
		buttonStart = new TextButton("Start", exitStyle);
		buttonStart.addListener(new ClickListener() {
			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				subject.notify(Event.EVENT_CLICK);
				Locator.getDevice().gameScreen();
				startGame();
				return false;
			}
		});

		buttonBack = new TextButton("Back", exitStyle);
		buttonBack.addListener(new ClickListener() {
			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				subject.notify(Event.EVENT_CLICK);
				Locator.getDevice().menuScreen();
				hide();
				return false;
			}
		});

		buttonConfirm = new TextButton("Unlock", confirmStyle);
		buttonConfirm.addListener(new ClickListener() {
			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				subject.notify(Event.EVENT_CLICK);
				if (track2Selected) {
					unlocked = track2.unlock();
				} else {
					switch (pUnlockType) {
					case RINGER:
						break;
					case APRIL:
						unlocked = aprilUnlock.unlock();
						break;
					case GEO:
						unlocked = geoUnlock.unlock();
						break;
					}
				}
				if (unlocked) {
					subject.notify(Event.EVENT_UNLOCK);
					hideUnlock();
				} else {
					subject.notify(Event.EVENT_INSUFFICIENT_COINS);
				}
				return false;
			}
		});

		buttonCancel = new TextButton("Cancel", confirmStyle);
		buttonCancel.addListener(new ClickListener() {
			@Override
			public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
				subject.notify(Event.EVENT_CLICK);
				hideUnlock();
				return false;
			}
		});

	}

	protected void startGame() {
		Gdx.input.setInputProcessor(null);
		subject.notify(Event.EVENT_MENU_TO_GAME);
		final GameScreen next = game.getGameScreen();
		next.loadLevel(pType, tType, bType);
		next.show();
		Screen transitionScreen = new TransitionScreen(game, menu, next, effects);
		game.setScreen(transitionScreen);
	}

	public void reset() {
		// reset boosts for next run
		bType.clear();
		magnet = false;
		shield = false;
		mult = false;
		magnetUnlock.reset();
		shieldUnlock.reset();
		multUnlock.reset();
	}

	public void render(float delta) {
		Gdx.gl.glClearColor(0,0,0, 1);
		Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
		sb.begin();
		sb.draw(background, 0, 0);
		bgPatch.draw(sb, ACTUAL_VIRTUAL_WIDTH * 0.02f, ACTUAL_VIRTUAL_HEIGHT * RINGER_Y, ACTUAL_VIRTUAL_WIDTH * 0.96f,
				ACTUAL_VIRTUAL_HEIGHT * 0.25f);
		bgPatch.draw(sb, ACTUAL_VIRTUAL_WIDTH * 0.02f, ACTUAL_VIRTUAL_HEIGHT * TRACK_Y, ACTUAL_VIRTUAL_WIDTH * 0.96f,
				ACTUAL_VIRTUAL_HEIGHT * 0.25f);
		bgPatch.draw(sb, ACTUAL_VIRTUAL_WIDTH * 0.02f, ACTUAL_VIRTUAL_HEIGHT * BOOST_Y, ACTUAL_VIRTUAL_WIDTH * 0.96f,
				ACTUAL_VIRTUAL_HEIGHT * 0.25f);
		sb.end();

		stage.act(delta);
		stage.draw();
		renderSelected();
		if (confirmUnlock) {
			sb.begin();
			patch.draw(sb, ACTUAL_VIRTUAL_WIDTH * 0.25f, ACTUAL_VIRTUAL_HEIGHT * 0.2f, ACTUAL_VIRTUAL_WIDTH * 0.4f,
					ACTUAL_VIRTUAL_HEIGHT * 0.5f);
			sb.end();
			stageUnlock.act(delta);
			stageUnlock.draw();
		}
		updateCoins();
	}

	private void updateCoins() {
		coins.setText("" + Locator.getCoins());

	}

	private void renderSelected() {
		float x = 0, y = 0;
		float trackX = 0, trackY = 0;
		switch (pType) {
		case RINGER:
			x = RINGER_X;
			y = RINGER_Y + 0.02f;
			break;
		case APRIL:
			x = RINGER_X + SEPARATION_X;
			y = RINGER_Y + 0.02f;
			break;
		case GEO:
			x = RINGER_X + SEPARATION_X * 2;
			y = RINGER_Y + 0.02f;
			break;
		default:
			break;
		}
		switch (tType) {
		case TRACK1:
			trackX = TRACK_X;
			trackY = TRACK_Y;
			break;
		case TRACK2:
			trackX = TRACK_X + SEPARATION_X;
			trackY = TRACK_Y;
			break;
		}

		selected.begin(ShapeType.Line);

		selected.setColor(Color.BLACK);
		// render selected parameters
		Gdx.gl.glLineWidth(4);
		selected.setColor(0.8f, 0.0f, 0, 1);
		// runner outline
		selected.rect(ACTUAL_VIRTUAL_WIDTH * x, ACTUAL_VIRTUAL_HEIGHT * (y), ACTUAL_VIRTUAL_WIDTH * SELECTED_WIDTH, ACTUAL_VIRTUAL_HEIGHT
				* SELECTED_HEIGHT);
		// track outline
		selected.rect(ACTUAL_VIRTUAL_WIDTH * trackX, ACTUAL_VIRTUAL_HEIGHT * (trackY + 0.02f), ACTUAL_VIRTUAL_WIDTH * SELECTED_WIDTH,
				ACTUAL_VIRTUAL_HEIGHT * SELECTED_HEIGHT);
		if (magnet) {
			selected.rect(ACTUAL_VIRTUAL_WIDTH * (RINGER_X), ACTUAL_VIRTUAL_HEIGHT * (BOOST_Y + 0.02f), ACTUAL_VIRTUAL_WIDTH
					* SELECTED_WIDTH, ACTUAL_VIRTUAL_HEIGHT * SELECTED_HEIGHT);
		}
		if (shield) {
			selected.rect(ACTUAL_VIRTUAL_WIDTH * (RINGER_X + SEPARATION_X), ACTUAL_VIRTUAL_HEIGHT * (BOOST_Y + 0.02f), ACTUAL_VIRTUAL_WIDTH
					* SELECTED_WIDTH, ACTUAL_VIRTUAL_HEIGHT * SELECTED_HEIGHT);
		}
		if (mult) {
			selected.rect(ACTUAL_VIRTUAL_WIDTH * (RINGER_X + (SEPARATION_X * 2)), ACTUAL_VIRTUAL_HEIGHT * (BOOST_Y + 0.02f),
					ACTUAL_VIRTUAL_WIDTH * SELECTED_WIDTH, ACTUAL_VIRTUAL_HEIGHT * SELECTED_HEIGHT);
		}
		selected.end();

	}

	public void resize(int width, int height) {
		stage.getViewport().update(width, height, true);
	}

	public void show() {
		effects.clear();
		effects.add(new FadeOutTransitionEffect(0.5f));
		effects.add(new FadeInTransitionEffect(0.5f));
		Gdx.input.setInputProcessor(stage);
		if (Locator.getCoins() >= 500) {
			subject.notify(Event.EVENT_HOARDER);
		}
	}

	public void hide() {
		Gdx.input.setInputProcessor(null);
		menu.showMenuScreen();
	}

	@Override
	public void onNotify(Event event) {
		switch (event) {
		case EVENT_RINGER_SELECTED:
			pType = PLAYER_TYPE.RINGER;
			track1.switchButton(pType);
			track2.switchButton(pType);
			track2Selected = false;
			background = Locator.getAssets().get(BACKGROUNDMAIN_RINGER, Texture.class);
			break;
		case EVENT_APRIL_SELECTED:
			if (aprilUnlock.isUnlocked()) {
				pType = PLAYER_TYPE.APRIL;
				track1.switchButton(pType);
				track2.switchButton(pType);
				background = Locator.getAssets().get(BACKGROUNDMAIN_APRIL, Texture.class);
			} else {
				track2Selected = false;
				pUnlockType = PLAYER_TYPE.APRIL;
				confirmUnlock();
				confirm.setText("Unlock April for " + AprilUnlock.APRIL_AMOUNT + " coins?");
			}
			break;
		case EVENT_GEO_SELECTED:
			if (geoUnlock.isUnlocked()) {
				pType = PLAYER_TYPE.GEO;
				track1.switchButton(pType);
				track2.switchButton(pType);
				background = Locator.getAssets().get(BACKGROUNDMAIN_GEO, Texture.class);
			} else {
				track2Selected = false;
				pUnlockType = PLAYER_TYPE.GEO;
				confirmUnlock();
				confirm.setText("Unlock Geo for " + GeoUnlock.GEO_AMOUNT + " coins?");
			}
			break;
		case EVENT_APRIL_UNLOCKED:
			track1.unlock(pType);
			break;
		case EVENT_GEO_UNLOCKED:
			track1.unlock(pType);
			break;
		case EVENT_MAGNET_SELECTED:
			if (!magnet) {
				bType.add(BOOST_TYPE.MAGNET);
			} else {
				bType.remove(BOOST_TYPE.MAGNET);
			}
			magnet = !magnet;
			break;
		case EVENT_SHIELD_SELECTED:
			if (!shield) {
				bType.add(BOOST_TYPE.SHIELD);
			} else {
				bType.remove(BOOST_TYPE.SHIELD);
			}
			shield = !shield;
			break;
		case EVENT_MULT_SELECTED:
			if (!mult) {
				bType.add(BOOST_TYPE.COIN_MULT);
			} else {
				bType.remove(BOOST_TYPE.COIN_MULT);
			}
			mult = !mult;
			break;
		case EVENT_TRACK2_UNLOCKED:

			break;
		case EVENT_TRACK1_SELECTED:
			tType = TRACKTYPE.TRACK1;
			break;
		case EVENT_TRACK2_SELECTED:
			if (track2Unlocked()) {
				tType = TRACKTYPE.TRACK2;
			} else {
				track2Selected = true;
				confirmUnlock();
				String name = pType.toString();
				String c = String.valueOf(name.charAt(0));
				name = name.toLowerCase().substring(1, pType.toString().length());
				c = c.concat(name);
				confirm.setText("Unlock " + c + "'s Track 2\n for " + Track2Unlock.TRACK2_AMOUNT + " coins?");
			}
			break;
		default:
			break;
		}
	}

	private boolean track2Unlocked() {
		switch (pType) {
		case RINGER:
			return Locator.getUnlocks().isRingerTrack2();
		case APRIL:
			return Locator.getUnlocks().isAprilTrack2();
		case GEO:
			return Locator.getUnlocks().isGeoTrack2();
		default:
			break;
		}
		return false;
	}

	private void hideUnlock() {
		Gdx.input.setInputProcessor(stage);
		confirmUnlock = false;
		buttonConfirm.setVisible(false);
		buttonConfirm.setDisabled(true);
		buttonCancel.setVisible(false);
		buttonCancel.setDisabled(true);
		confirm.setVisible(false);
	}

	private void confirmUnlock() {
		Gdx.input.setInputProcessor(stageUnlock);
		confirmUnlock = true;
		buttonConfirm.setVisible(true);
		buttonConfirm.setDisabled(false);
		buttonCancel.setVisible(true);
		buttonCancel.setDisabled(false);
		confirm.setVisible(true);
	}

	public PLAYER_TYPE getPType() {
		return pType;
	}
}
